home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2005 October / PCWOCT05.iso / Software / FromTheMag / XAMPP 1.4.14 / xampp-win32-1.4.14-installer.exe / xampp / php / pear / data / HTML_TreeMenu / TreeMenu.js
Text File  |  2004-03-24  |  22KB  |  698 lines

  1. // +-----------------------------------------------------------------------+
  2. // | Copyright (c) 2002-2003, Richard Heyes, Harald Radi                        |
  3. // | All rights reserved.                                                  |
  4. // |                                                                       |
  5. // | Redistribution and use in source and binary forms, with or without    |
  6. // | modification, are permitted provided that the following conditions    |
  7. // | are met:                                                              |
  8. // |                                                                       |
  9. // | o Redistributions of source code must retain the above copyright      |
  10. // |   notice, this list of conditions and the following disclaimer.       |
  11. // | o Redistributions in binary form must reproduce the above copyright   |
  12. // |   notice, this list of conditions and the following disclaimer in the |
  13. // |   documentation and/or other materials provided with the distribution.|
  14. // | o The names of the authors may not be used to endorse or promote      |
  15. // |   products derived from this software without specific prior written  |
  16. // |   permission.                                                         |
  17. // |                                                                       |
  18. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
  19. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
  20. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
  21. // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
  22. // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
  23. // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
  24. // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
  25. // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
  26. // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
  27. // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
  28. // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
  29. // |                                                                       |
  30. // +-----------------------------------------------------------------------+
  31. // | Author: Richard Heyes <richard@phpguru.org>                           |
  32. // |         Harald Radi <harald.radi@nme.at>                              |
  33. // +-----------------------------------------------------------------------+
  34. //
  35. // $Id: TreeMenu.js,v 1.18 2003/12/20 13:33:09 richard Exp $
  36.  
  37. /**
  38. * Function to create copies of objects which are
  39. * normally passed around by references (Arrays for example)
  40. */
  41. function arrayCopy(input)
  42. {
  43.     var output = new Array(input.length);
  44.  
  45.     for (i in input) {
  46.         if (typeof(input[i]) == 'array') {
  47.             output[i] = arrayCopy(input[i]);
  48.         } else {
  49.             output[i] = input[i];
  50.         }
  51.     }
  52.  
  53.     return output;
  54. }
  55.  
  56. /**
  57. * TreeMenu class
  58. */
  59.     function TreeMenu(iconpath, myname, linkTarget, defaultClass, usePersistence, noTopLevelImages)
  60.     {
  61.         // Properties
  62.         this.iconpath         = iconpath;
  63.         this.myname           = myname;
  64.         this.linkTarget       = linkTarget;
  65.         this.defaultClass     = defaultClass;
  66.         this.usePersistence   = usePersistence;
  67.         this.noTopLevelImages = noTopLevelImages;
  68.         this.n                = new Array();
  69.         this.output           = '';
  70.  
  71.         this.nodeRefs       = new Array();
  72.         this.branches       = new Array();
  73.         this.branchStatus   = new Array();
  74.         this.layerRelations = new Array();
  75.         this.childParents   = new Array();
  76.         this.cookieStatuses = new Array();
  77.  
  78.         this.preloadImages();
  79.     }
  80.  
  81. /**
  82. * Adds a node to the tree
  83. */
  84.     TreeMenu.prototype.addItem = function (newNode)
  85.     {
  86.         newIndex = this.n.length;
  87.         this.n[newIndex] = newNode;
  88.         
  89.         return this.n[newIndex];
  90.     }
  91.  
  92. /**
  93. * Preload images hack for Mozilla
  94. */
  95.     TreeMenu.prototype.preloadImages = function ()
  96.     {
  97.         var plustop    = new Image; plustop.src    = this.iconpath + '/plustop.gif';
  98.         var plusbottom = new Image; plusbottom.src = this.iconpath + '/plusbottom.gif';
  99.         var plus       = new Image; plus.src       = this.iconpath + '/plus.gif';
  100.     
  101.         var minustop    = new Image; minustop.src    = this.iconpath + '/minustop.gif';
  102.         var minusbottom = new Image; minusbottom.src = this.iconpath + '/minusbottom.gif';
  103.         var minus       = new Image; minus.src       = this.iconpath + '/minus.gif';
  104.     
  105.         var branchtop    = new Image; branchtop.src    = this.iconpath + '/branchtop.gif';
  106.         var branchbottom = new Image; branchbottom.src = this.iconpath + '/branchbottom.gif';
  107.         var branch       = new Image; branch.src       = this.iconpath + '/branch.gif';
  108.     
  109.         var linebottom = new Image; linebottom.src = this.iconpath + '/linebottom.gif';
  110.         var line       = new Image; line.src       = this.iconpath + '/line.gif';
  111.     }
  112.  
  113. /**
  114. * Main function that draws the menu and assigns it
  115. * to the layer (or document.write()s it)
  116. */
  117.     TreeMenu.prototype.drawMenu = function ()// OPTIONAL ARGS: nodes = [], level = [], prepend = '', expanded = false, visbility = 'inline', parentLayerID = null
  118.     {
  119.         /**
  120.         * Necessary variables
  121.         */
  122.         var output        = '';
  123.         var modifier      = '';
  124.         var layerID       = '';
  125.         var parentLayerID = '';
  126.     
  127.         /**
  128.         * Parse any optional arguments
  129.         */
  130.         var nodes         = arguments[0] ? arguments[0] : this.n
  131.         var level         = arguments[1] ? arguments[1] : [];
  132.         var prepend       = arguments[2] ? arguments[2] : '';
  133.         var expanded      = arguments[3] ? arguments[3] : false;
  134.         var visibility    = arguments[4] ? arguments[4] : 'inline';
  135.         var parentLayerID = arguments[5] ? arguments[5] : null;
  136.  
  137.         var currentlevel  = level.length;
  138.  
  139.         for (var i=0; i<nodes.length; i++) {
  140.         
  141.             level[currentlevel] = i+1;
  142.             layerID = this.myname + '_' + 'node_' + this.implode('_', level);
  143.  
  144.             /**
  145.             * Store this object in the nodeRefs array
  146.             */
  147.             this.nodeRefs[layerID] = nodes[i];
  148.  
  149.             /**
  150.             * Store the child/parent relationship
  151.             */
  152.             this.childParents[layerID] = parentLayerID;
  153.     
  154.             /**
  155.             * Gif modifier
  156.             */
  157.             if (i == 0 && parentLayerID == null) {
  158.                 modifier = nodes.length > 1 ? "top" : 'single';
  159.             } else if(i == (nodes.length-1)) {
  160.                 modifier = "bottom";
  161.             } else {
  162.                 modifier = "";
  163.             }
  164.     
  165.             /**
  166.             * Single root branch is always expanded
  167.             */
  168.             if (!this.doesMenu() || (parentLayerID == null && (nodes.length == 1 || this.noTopLevelImages))) {
  169.                 expanded = true;
  170.     
  171.             } else if (nodes[i].expanded) {
  172.                 expanded = true;
  173.     
  174.             } else {
  175.                 expanded = false;
  176.             }
  177.     
  178.             /**
  179.             * Make sure visibility is correct based on parent status
  180.             */
  181.             visibility =  this.checkParentVisibility(layerID) ? visibility : 'none';
  182.  
  183.             /**
  184.             * Setup branch status and build an indexed array
  185.             * of branch layer ids
  186.             */
  187.             if (nodes[i].n.length > 0) {
  188.                 this.branchStatus[layerID] = expanded;
  189.                 this.branches[this.branches.length] = layerID;
  190.             }
  191.     
  192.             /**
  193.             * Setup toggle relationship
  194.             */
  195.             if (!this.layerRelations[parentLayerID]) {
  196.                 this.layerRelations[parentLayerID] = new Array();
  197.             }
  198.             this.layerRelations[parentLayerID][this.layerRelations[parentLayerID].length] = layerID;
  199.     
  200.             /**
  201.             * Branch images
  202.             */
  203.             var gifname  = nodes[i].n.length && this.doesMenu() && nodes[i].isDynamic ? (expanded ? 'minus' : 'plus') : 'branch';
  204.             var iconName = expanded && nodes[i].expandedIcon ? nodes[i].expandedIcon : nodes[i].icon;
  205.             var iconimg  = nodes[i].icon ? this.stringFormat('<img src="{0}/{1}" width="20" height="20" align="top" id="icon_{2}">', this.iconpath, iconName, layerID) : '';
  206.             
  207.             /**
  208.             * Add event handlers
  209.             */
  210.             var eventHandlers = "";
  211.             for (j in nodes[i].events) {
  212.                 eventHandlers += this.stringFormat('{0}="{1}" ', j, nodes[i].events[j]);
  213.             }
  214.  
  215.             /**
  216.             * Build the html to write to the document
  217.             * IMPORTANT:
  218.             * document.write()ing the string: '<div style="display:...' will screw up nn4.x
  219.             */
  220.             var layerTag  = this.doesMenu() ? this.stringFormat('<div id="{0}" style="display: {1}" class="{2}">', layerID, visibility, (nodes[i].cssClass ? nodes[i].cssClass : this.defaultClass)) : this.stringFormat('<div class="{0}">', nodes[i].cssClass ? nodes[i].cssClass : this.defaultClass);
  221.             var onMDown   = this.doesMenu() && nodes[i].n.length  && nodes[i].isDynamic ? this.stringFormat('onmousedown="{0}.toggleBranch(\'{1}\', true)" style="cursor: pointer; cursor: hand"', this.myname, layerID) : '';
  222.             var imgTag    = this.stringFormat('<img src="{0}/{1}{2}.gif" width="20" height="20" align="top" border="0" name="img_{3}" {4}>', this.iconpath, gifname, modifier, layerID, onMDown);
  223.             var linkTarget= nodes[i].linkTarget ? nodes[i].linkTarget : this.linkTarget;
  224.             var linkStart = nodes[i].link ? this.stringFormat('<a href="{0}" target="{1}">', nodes[i].link, linkTarget) : '';
  225.  
  226.             var linkEnd   = nodes[i].link ? '</a>' : '';
  227.  
  228.             this.output += this.stringFormat('{0}<nobr>{1}{2}{3}{4}<span {5}>{6}</span>{7}</nobr><br></div>',
  229.                               layerTag,
  230.                               prepend,
  231.                               parentLayerID == null && (nodes.length == 1 || this.noTopLevelImages) ? '' : imgTag,
  232.                               iconimg,
  233.                               linkStart,
  234.                               eventHandlers,
  235.                               nodes[i].title,
  236.                               linkEnd);
  237.  
  238.             /**
  239.             * Traverse sub nodes ?
  240.             */
  241.             if (nodes[i].n.length) {
  242.                 /**
  243.                 * Determine what to prepend. If there is only one root
  244.                 * node then the prepend to pass to children is nothing.
  245.                 * Otherwise it depends on where we are in the tree.
  246.                 */
  247.                 if (parentLayerID == null && (nodes.length == 1 || this.noTopLevelImages)) {
  248.                     var newPrepend = '';
  249.     
  250.                 } else if (i < (nodes.length - 1)) {
  251.                     var newPrepend = prepend + this.stringFormat('<img src="{0}/line.gif" width="20" height="20" align="top">', this.iconpath);
  252.     
  253.                 } else {
  254.                     var newPrepend = prepend + this.stringFormat('<img src="{0}/linebottom.gif" width="20" height="20" align="top">', this.iconpath);
  255.                 }
  256.  
  257.                 this.drawMenu(nodes[i].n,
  258.                               arrayCopy(level),
  259.                               newPrepend,
  260.                               nodes[i].expanded,
  261.                               expanded ? 'inline' : 'none',
  262.                               layerID);
  263.             }
  264.         }
  265.     }
  266.  
  267. /**
  268. * Writes the output generated by drawMenu() to the page
  269. */
  270.     TreeMenu.prototype.writeOutput = function ()
  271.     {
  272.         document.write(this.output);
  273.     }
  274.  
  275. /**
  276. * Toggles a branches visible status. Called from resetBranches()
  277. * and also when a +/- graphic is clicked.
  278. */
  279.     TreeMenu.prototype.toggleBranch = function (layerID, updateStatus) // OPTIONAL ARGS: fireEvents = true
  280.     {
  281.         var currentDisplay = this.getLayer(layerID).style.display;
  282.         var newDisplay     = (this.branchStatus[layerID] && currentDisplay == 'inline') ? 'none' : 'inline';
  283.         var fireEvents     = arguments[2] != null ? arguments[2] : true;
  284.  
  285.         for (var i=0; i<this.layerRelations[layerID].length; i++) {
  286.  
  287.             if (this.branchStatus[this.layerRelations[layerID][i]]) {
  288.                 this.toggleBranch(this.layerRelations[layerID][i], false);
  289.             }
  290.     
  291.             this.getLayer(this.layerRelations[layerID][i]).style.display = newDisplay;
  292.         }
  293.     
  294.         if (updateStatus) {
  295.             this.branchStatus[layerID] = !this.branchStatus[layerID];
  296.     
  297.             /**
  298.             * Persistence
  299.             */
  300.             if (this.doesPersistence() && !arguments[2] && this.usePersistence) {
  301.                 this.setExpandedStatusForCookie(layerID, this.branchStatus[layerID]);
  302.             }
  303.  
  304.             /**
  305.             * Fire custom events
  306.             */
  307.             if (fireEvents) {
  308.                 nodeObject = this.nodeRefs[layerID];
  309.     
  310.                 if (nodeObject.ontoggle != null) {
  311.                     eval(nodeObject.ontoggle);
  312.                 }
  313.                 
  314.                 if (newDisplay == 'none' && nodeObject.oncollapse != null) {
  315.                     eval(nodeObject.oncollapse);
  316.                 } else if (newDisplay == 'inline' && nodeObject.onexpand != null){
  317.                     eval(nodeObject.onexpand);
  318.                 }
  319.             }
  320.  
  321.             // Swap image
  322.             this.swapImage(layerID);
  323.         }
  324.  
  325.         // Swap icon
  326.         this.swapIcon(layerID);
  327.     }
  328.  
  329. /**
  330. * Swaps the plus/minus branch images
  331. */
  332.     TreeMenu.prototype.swapImage = function (layerID)
  333.     {
  334.         var imgSrc = document.images['img_' + layerID].src;
  335.     
  336.         var re = /^(.*)(plus|minus)(bottom|top|single)?.gif$/
  337.         if (matches = imgSrc.match(re)) {
  338.     
  339.             document.images['img_' + layerID].src = this.stringFormat('{0}{1}{2}{3}',
  340.                                                             matches[1],
  341.                                                             matches[2] == 'plus' ? 'minus' : 'plus',
  342.                                                             matches[3] ? matches[3] : '',
  343.                                                             '.gif');
  344.         }
  345.     }
  346.  
  347. /**
  348. * Swaps the icon for the expanded icon if one
  349. * has been supplied.
  350. */
  351.     TreeMenu.prototype.swapIcon = function (layerID)
  352.     {
  353.         if (document.images['icon_' + layerID]) {
  354.             var imgSrc = document.images['icon_' + layerID].src;
  355.     
  356.             if (this.nodeRefs[layerID].icon && this.nodeRefs[layerID].expandedIcon) {
  357.                 var newSrc = (imgSrc.indexOf(this.nodeRefs[layerID].expandedIcon) == -1 ? this.nodeRefs[layerID].expandedIcon : this.nodeRefs[layerID].icon);
  358.     
  359.                 document.images['icon_' + layerID].src = this.iconpath + '/' + newSrc;
  360.             }
  361.         }
  362.     }
  363.  
  364. /**
  365. * Can the browser handle the dynamic menu?
  366. */
  367.     TreeMenu.prototype.doesMenu = function ()
  368.     {
  369.         return (is_ie4up || is_nav6up || is_gecko || is_opera7);
  370.     }
  371.  
  372. /**
  373. * Can the browser handle save the branch status
  374. */
  375.     TreeMenu.prototype.doesPersistence = function ()
  376.     {
  377.         return (is_ie4up || is_gecko || is_nav6up || is_opera7);
  378.     }
  379.  
  380. /**
  381. * Returns the appropriate layer accessor
  382. */
  383.     TreeMenu.prototype.getLayer = function (layerID)
  384.     {
  385.         if (is_ie4) {
  386.             return document.all(layerID);
  387.     
  388.         } else if (document.getElementById(layerID)) {
  389.             return document.getElementById(layerID);
  390.     
  391.         } else if (document.all(layerID)) {
  392.             return document.all(layerID);
  393.         }
  394.     }
  395.  
  396. /**
  397. * Save the status of the layer
  398. */
  399.     TreeMenu.prototype.setExpandedStatusForCookie = function (layerID, expanded)
  400.     {
  401.         this.cookieStatuses[layerID] = expanded;
  402.         this.saveCookie();
  403.     }
  404.  
  405. /**
  406. * Load the status of the layer
  407. */
  408.     TreeMenu.prototype.getExpandedStatusFromCookie = function (layerID)
  409.     {
  410.         if (this.cookieStatuses[layerID]) {
  411.             return this.cookieStatuses[layerID];
  412.         }
  413.  
  414.         return false;
  415.     }
  416.  
  417. /**
  418. * Saves the cookie that holds which branches are expanded.
  419. * Only saves the details of the branches which are expanded.
  420. */
  421.     TreeMenu.prototype.saveCookie = function ()
  422.     {
  423.         var cookieString = new Array();
  424.  
  425.         for (var i in this.cookieStatuses) {
  426.             if (this.cookieStatuses[i] == true) {
  427.                 cookieString[cookieString.length] = i;
  428.             }
  429.         }
  430.         
  431.         document.cookie = 'TreeMenuBranchStatus=' + cookieString.join(':');
  432.     }
  433.  
  434. /**
  435. * Reads cookie parses it for status info and
  436. * stores that info in the class member.
  437. */
  438.     TreeMenu.prototype.loadCookie = function ()
  439.     {
  440.         var cookie = document.cookie.split('; ');
  441.  
  442.         for (var i=0; i < cookie.length; i++) {
  443.             var crumb = cookie[i].split('=');
  444.             if ('TreeMenuBranchStatus' == crumb[0] && crumb[1]) {
  445.                 var expandedBranches = crumb[1].split(':');
  446.                 for (var j=0; j<expandedBranches.length; j++) {
  447.                     this.cookieStatuses[expandedBranches[j]] = true;
  448.                 }
  449.             }
  450.         }
  451.     }
  452.  
  453. /**
  454. * Reset branch status
  455. */
  456.     TreeMenu.prototype.resetBranches = function ()
  457.     {
  458.         if (!this.doesPersistence()) {
  459.             return false;
  460.         }
  461.         
  462.         this.loadCookie();
  463.  
  464.         for (var i=0; i<this.branches.length; i++) {
  465.             var status = this.getExpandedStatusFromCookie(this.branches[i]);
  466.             // Only update if it's supposed to be expanded and it's not already
  467.             if (status == true && this.branchStatus[this.branches[i]] != true) {
  468.                 if (this.checkParentVisibility(this.branches[i])) {
  469.                     this.toggleBranch(this.branches[i], true, false);
  470.                 } else {
  471.                     this.branchStatus[this.branches[i]] = true;
  472.                     this.swapImage(this.branches[i]);
  473.                 }
  474.             }
  475.         }
  476.     }
  477.  
  478. /**
  479. * Checks whether a branch should be open
  480. * or not based on its parents' status
  481. */
  482.     TreeMenu.prototype.checkParentVisibility = function (layerID)
  483.     {
  484.         if (this.in_array(this.childParents[layerID], this.branches)
  485.             && this.branchStatus[this.childParents[layerID]]
  486.             && this.checkParentVisibility(this.childParents[layerID]) ) {
  487.             
  488.             return true;
  489.     
  490.         } else if (this.childParents[layerID] == null) {
  491.             return true;
  492.         }
  493.         
  494.         return false;
  495.     }
  496.  
  497. /**
  498. * New C# style string formatter
  499. */
  500.     TreeMenu.prototype.stringFormat = function (strInput)
  501.     {
  502.         var idx = 0;
  503.     
  504.         for (var i=1; i<arguments.length; i++) {
  505.             while ((idx = strInput.indexOf('{' + (i - 1) + '}', idx)) != -1) {
  506.                 strInput = strInput.substring(0, idx) + arguments[i] + strInput.substr(idx + 3);
  507.             }
  508.         }
  509.         
  510.         return strInput;
  511.     }
  512.  
  513. /**
  514. * Also much adored, the PHP implode() function
  515. */
  516.     TreeMenu.prototype.implode = function (seperator, input)
  517.     {
  518.         var output = '';
  519.     
  520.         for (var i=0; i<input.length; i++) {
  521.             if (i == 0) {
  522.                 output += input[i];
  523.             } else {
  524.                 output += seperator + input[i];
  525.             }
  526.         }
  527.         
  528.         return output;
  529.     }
  530.  
  531. /**
  532. * Aah, all the old favourites are coming out...
  533. */
  534.     TreeMenu.prototype.in_array = function (item, arr)
  535.     {
  536.         for (var i=0; i<arr.length; i++) {
  537.             if (arr[i] == item) {
  538.                 return true;
  539.             }
  540.         }
  541.     
  542.         return false;
  543.     }
  544.  
  545. /**
  546. * TreeNode Class
  547. */
  548.     function TreeNode(title, icon, link, expanded, isDynamic, cssClass, linkTarget, expandedIcon)
  549.     {
  550.         this.title        = title;
  551.         this.icon         = icon;
  552.         this.expandedIcon = expandedIcon;
  553.         this.link         = link;
  554.         this.expanded     = expanded;
  555.         this.isDynamic    = isDynamic;
  556.         this.cssClass     = cssClass;
  557.         this.linkTarget   = linkTarget;
  558.         this.n            = new Array();
  559.         this.events       = new Array();
  560.         this.handlers     = null;
  561.         this.oncollapse   = null;
  562.         this.onexpand     = null;
  563.         this.ontoggle     = null;
  564.     }
  565.  
  566. /**
  567. * Adds a node to an already existing node
  568. */
  569.     TreeNode.prototype.addItem = function (newNode)
  570.     {
  571.         newIndex = this.n.length;
  572.         this.n[newIndex] = newNode;
  573.         
  574.         return this.n[newIndex];
  575.     }
  576.  
  577. /**
  578. * Sets an event for this particular node
  579. */
  580.     TreeNode.prototype.setEvent = function (eventName, eventHandler)
  581.     {
  582.         switch (eventName.toLowerCase()) {
  583.             case 'onexpand':
  584.                 this.onexpand = eventHandler;
  585.                 break;
  586.  
  587.             case 'oncollapse':
  588.                 this.oncollapse = eventHandler;
  589.                 break;
  590.  
  591.             case 'ontoggle':
  592.                 this.ontoggle = eventHandler;
  593.                 break;
  594.  
  595.             default:
  596.                 this.events[eventName] = eventHandler;
  597.         }
  598.     }
  599.  
  600. /**
  601. * That's the end of the tree classes. What follows is
  602. * the browser detection code.
  603. */
  604.     
  605.  
  606. //<!--
  607. // Ultimate client-side JavaScript client sniff. Version 3.03
  608. // (C) Netscape Communications 1999-2001.  Permission granted to reuse and distribute.
  609. // Revised 17 May 99 to add is_nav5up and is_ie5up (see below).
  610. // Revised 20 Dec 00 to add is_gecko and change is_nav5up to is_nav6up
  611. //                      also added support for IE5.5 Opera4&5 HotJava3 AOLTV
  612. // Revised 22 Feb 01 to correct Javascript Detection for IE 5.x, Opera 4,
  613. //                      correct Opera 5 detection
  614. //                      add support for winME and win2k
  615. //                      synch with browser-type-oo.js
  616. // Revised 26 Mar 01 to correct Opera detection
  617. // Revised 02 Oct 01 to add IE6 detection
  618.  
  619. // Everything you always wanted to know about your JavaScript client
  620. // but were afraid to ask. Creates "is_" variables indicating:
  621. // (1) browser vendor:
  622. //     is_nav, is_ie, is_opera, is_hotjava, is_webtv, is_TVNavigator, is_AOLTV
  623. // (2) browser version number:
  624. //     is_major (integer indicating major version number: 2, 3, 4 ...)
  625. //     is_minor (float   indicating full  version number: 2.02, 3.01, 4.04 ...)
  626. // (3) browser vendor AND major version number
  627. //     is_nav2, is_nav3, is_nav4, is_nav4up, is_nav6, is_nav6up, is_gecko, is_ie3,
  628. //     is_ie4, is_ie4up, is_ie5, is_ie5up, is_ie5_5, is_ie5_5up, is_ie6, is_ie6up, is_hotjava3, is_hotjava3up,
  629. //     is_opera2, is_opera3, is_opera4, is_opera5, is_opera5up
  630. // (4) JavaScript version number:
  631. //     is_js (float indicating full JavaScript version number: 1, 1.1, 1.2 ...)
  632. // (5) OS platform and version:
  633. //     is_win, is_win16, is_win32, is_win31, is_win95, is_winnt, is_win98, is_winme, is_win2k
  634. //     is_os2
  635. //     is_mac, is_mac68k, is_macppc
  636. //     is_unix
  637. //     is_sun, is_sun4, is_sun5, is_suni86
  638. //     is_irix, is_irix5, is_irix6
  639. //     is_hpux, is_hpux9, is_hpux10
  640. //     is_aix, is_aix1, is_aix2, is_aix3, is_aix4
  641. //     is_linux, is_sco, is_unixware, is_mpras, is_reliant
  642. //     is_dec, is_sinix, is_freebsd, is_bsd
  643. //     is_vms
  644. //
  645. // See http://www.it97.de/JavaScript/JS_tutorial/bstat/navobj.html and
  646. // http://www.it97.de/JavaScript/JS_tutorial/bstat/Browseraol.html
  647. // for detailed lists of userAgent strings.
  648. //
  649. // Note: you don't want your Nav4 or IE4 code to "turn off" or
  650. // stop working when new versions of browsers are released, so
  651. // in conditional code forks, use is_ie5up ("IE 5.0 or greater")
  652. // is_opera5up ("Opera 5.0 or greater") instead of is_ie5 or is_opera5
  653. // to check version in code which you want to work on future
  654. // versions.
  655.  
  656. /**
  657. * Severly curtailed all this as only certain elements
  658. * are required by TreeMenu, specifically:
  659. *  o is_ie4up
  660. *  o is_nav6up
  661. *  o is_gecko
  662. */
  663.  
  664.     // convert all characters to lowercase to simplify testing
  665.     var agt=navigator.userAgent.toLowerCase();
  666.  
  667.     // *** BROWSER VERSION ***
  668.     // Note: On IE5, these return 4, so use is_ie5up to detect IE5.
  669.     var is_major = parseInt(navigator.appVersion);
  670.     var is_minor = parseFloat(navigator.appVersion);
  671.  
  672.     // Note: Opera and WebTV spoof Navigator.  We do strict client detection.
  673.     // If you want to allow spoofing, take out the tests for opera and webtv.
  674.     var is_nav  = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
  675.                 && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
  676.                 && (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1));
  677.     var is_nav6up = (is_nav && (is_major >= 5));
  678.     var is_gecko = (agt.indexOf('gecko') != -1);
  679.  
  680.  
  681.     var is_ie     = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
  682.     var is_ie4    = (is_ie && (is_major == 4) && (agt.indexOf("msie 4")!=-1) );
  683.     var is_ie4up  = (is_ie && (is_major >= 4));
  684.     
  685.     var is_opera  = (agt.indexOf("opera") != -1);
  686.     var is_opera7 = is_opera && (agt.indexOf("opera 7") != -1);
  687.  
  688.     // Patch from Harald Fielker
  689.     if (agt.indexOf('konqueror') != -1) {
  690.         var is_nav    = false;
  691.         var is_nav6up = false;
  692.         var is_gecko  = false;
  693.         var is_ie     = true;
  694.         var is_ie4    = true;
  695.         var is_ie4up  = true;
  696.     }
  697. //--> end hide JavaScript
  698.